package com.dhms.vostok1.ui.webview

import android.net.Uri
import android.util.Log
import android.webkit.JavascriptInterface
import android.webkit.WebView
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.findFragment
import androidx.navigation.fragment.findNavController
import com.alibaba.android.arouter.launcher.ARouter
import com.dhms.uikit.PdfViewerActivity
import com.dhms.uikit.TimePickerBottomSheet
import com.dhms.uikit.media.MediaActivity
import com.dhms.uikit.select_bottom_sheet.SelectBottomSheet
import com.dhms.uikit.select_bottom_sheet.SelectItem
import com.dhms.vostok1.data.NativeParamsData
import com.dhms.vostok1.data.maintenance.TaskModuleType
import com.dhms.vostok1.network.MoshiObject.jsonAdapter
import com.dhms.vostok1.routes.MineRoute
import com.dhms.vostok1.ui.main.MainActivityInterface
import com.dhms.vostok1.ui.main.device.SelectDeviceBottomSheet
import com.dhms.vostok1.utils.FlutterModule
import com.dhms.vostok1.utils.Utils.Companion.parseAddress
import com.dhms.vostok1.utils.Utils.Companion.parseOssUrl
import com.dhms.vostok1.utils.getLongValue
import com.dhms.webview.R
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import java.util.*

enum class NativePageType(val code: Int) {
    ///设备详情
    DeviceDetail(1),

    ///润滑详情
    LubricationDetail(2),

    ///维保详情
    MaintenanceDetail(3),

    ///点检详情
    SpotPatrolDetail(4),

    ///检修创建
    RepairCreate(5);

    companion object {
        fun fromInt(type: Int) = NativePageType.values()
            .associateBy(NativePageType::code)[type]
    }
}


class WebViewInterface(private val webView: WebView) {

    private val fragment: WebViewFragment = webView.findFragment()

    init {
        if (fragment.requireActivity() is MainActivityInterface) {

            (fragment.requireActivity() as MainActivityInterface).memberEventObserve(fragment.viewLifecycleOwner) {
                sendCallback(it as String)
            }
        }
    }

    private val onBackPressedCallback by lazy {
        object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {}
        }
    }

    /**
     * Navigate Up.
     */
    @JavascriptInterface
    fun navigateUp() {
        fragment.apply {
            val activity = requireActivity()
            if (findNavController().previousBackStackEntry?.destination?.id in ((activity as MainActivityInterface).getHomeNavList())
                && activity is MainActivityInterface) {
                (activity as MainActivityInterface ).bottomNavigationShow()
//                activity.runOnUiThread {
//                    activity.binding.bottomNavigation.show()
//                }
            }
            findNavController().navigateUp()
        }
    }

    /**
     * Trigger Back Event.
     */
    @JavascriptInterface
    fun back() {
        fragment.requireActivity().apply {
            runOnUiThread {
                onBackPressed()
            }
        }
    }

    /**
     * Logout.
     */
    @JavascriptInterface
    fun logout() {
        (fragment.requireActivity() as MainActivityInterface).logout()
    }

    /**
     * Block the callback of the back event.
     * Should call releaseBackCallback() when the blocking is useless like the case that a dialog misses.
     */
    @JavascriptInterface
    fun blockBackCallback() {
        fragment.requireActivity().onBackPressedDispatcher.addCallback(onBackPressedCallback)
    }

    /**
     * Release the callback of the back event.
     */
    @JavascriptInterface
    fun releaseBackCallback() {
        onBackPressedCallback.remove()
    }

    /**
     * Show the time picker.
     * @param timePickerType
     *  1: show full date and time picker.
     *  2: show full date picker and time picker without second picker.
     *  3: show data picker only.
     * @param initialTime the default time of time picker
     */
    @JavascriptInterface
    fun showTimePicker(timePickerType: Int, initialTime: Long) {
        val calendar = Calendar.getInstance()
        calendar.time = Date(initialTime * 1000)
        val timePickerBottomSheet = TimePickerBottomSheet().setDefaultTime(calendar)

        if (timePickerBottomSheet.isAdded) {
            return
        }
        when (timePickerType) {
            1 -> timePickerBottomSheet.setIsShowSecondPicker(true)
            3 -> timePickerBottomSheet.setIsJustShowDatePicker(true)
            else -> {}
        }

        timePickerBottomSheet.setOnTimeSelectedListener {
            sendCallback((it.time.time / 1000).toString())
        }.show(fragment.requireActivity().supportFragmentManager, TAG)
    }

    /**
     * Preview medias.
     * @param mediaIndex Current media's index of the media list.
     * @param mediaList The media list to preview.
     */
    @JavascriptInterface
    fun previewMedias(mediaIndex: Int, mediaList: Array<String>) {
        MediaActivity.startActivity(
            fragment.requireContext(),
            fragment.requireActivity(),
            UUID.randomUUID().toString(),
            MediaActivity.Companion.IntentType.MANAGE,
            mediaList.map {
                parseAddress(it)
            }.toTypedArray(),
            mediaIndex,
            true
        )
    }

    /**
     * Show the bottom device picker.
     * @param selectedDevicesString A json string of selected devices which to set the default checked items.
     * @param isMultiSelectMode Set multi-select mode.
     */
    @JavascriptInterface
    fun showCategoryDeviceSelector(selectedDevicesString: String, isMultiSelectMode: Boolean) {
        try {
            val selectItemsType =
                Types.newParameterizedType(List::class.java, SelectItem::class.java)
            val moshiAdapter = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
                .adapter<List<SelectItem>>(selectItemsType)
            val selectedDevices = moshiAdapter.fromJson(selectedDevicesString)
            val selectDeviceBottomSheet = SelectDeviceBottomSheet(
                isMultiSelectMode,
                selectedDevices ?: listOf(),
            ) {
                sendCallback(moshiAdapter.toJson(it.map { deviceItem ->

                    SelectItem().apply {
                        this.name = deviceItem.de_name
                        this.id = deviceItem.de_id
                    }
                }))
            }
            selectDeviceBottomSheet.show(fragment.childFragmentManager, TAG)
        } catch (e: Exception) {
            Log.e(TAG, "${e.message}", e)
            (fragment.requireActivity() as MainActivityInterface).showToast(
                R.drawable.ic_fail,
                "设备数据有误，请联系管理员",
                timeOut = 1
            )
        }
    }

    /**
     * Show a base bottom sheet selector.
     * @param selectorTitle Set the title of the selector.
     * @param allItemsString All items to be selected.
     * @param selectedItemsString A json string of selected items which to set the default checked items.
     * @param isMultiSelectMode Set multi-select mode.
     */
    @JavascriptInterface
    fun showBottomSheetSelector(
        selectorTitle: String,
        allItemsString: String,
        selectedItemsString: String,
        isMultiSelectMode: Boolean
    ) {
        try {
            val selectItemsType =
                Types.newParameterizedType(List::class.java, SelectItem::class.java)
            val moshiAdapter = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
                .adapter<List<SelectItem>>(selectItemsType)
            val selectedItems = moshiAdapter.fromJson(selectedItemsString)
            val allItems = moshiAdapter.fromJson(allItemsString)
            val bottomSheet = SelectBottomSheet(
                allItems ?: listOf(),
                selectorTitle,
                isMultiSelectMode
            ) {
                sendCallback(moshiAdapter.toJson(it.toList()))
            }.setSelectedList(selectedItems?.toSet() ?: setOf())
            bottomSheet.show(fragment.childFragmentManager, TAG)
        } catch (e: Exception) {
            Log.e(TAG, "${e.message}", e)
            (fragment.requireActivity() as MainActivityInterface).showToast(
                R.drawable.ic_fail,
                "设备数据有误，请联系管理员",
                timeOut = 1
            )
        }
    }

    /**
     * Preview a PDF file.
     * @param url PDF file's url.
     */
    @JavascriptInterface
    fun previewPDF(url: String) {
        PdfViewerActivity.startActivity(
            Uri.parse(parseOssUrl(url)), fragment.requireActivity()
        )
    }

    /**
     * open native page
     * @param nativePage:  1: 设备详情 2: 润滑详情 3: 维保详情 4.点检详情
     * @param params: groupId: String, taskId: String , deviceId: Long
     */
    @JavascriptInterface
    fun openNativePage(nativePage: Int, params: String) {
        val map = jsonAdapter.fromJson(params)
        NativePageType.fromInt(nativePage)?.let { page ->
            when (page) {
                NativePageType.DeviceDetail -> {
                    map?.get("deviceId")?.toString()?.toLongOrNull().let { deviceId ->

                    }
                    //deviceViewModel.setCurrentDevice(deviceViewModel.filteredDeviceListData.value?.get(index))
                    //deviceViewModel.clearDevicePartsData()

                    fragment.requireActivity().apply {
                        runOnUiThread {
                            try {
                                val action =
                                    WebViewFragmentDirections.actionWebViewFragmentToDeviceDetailFragment()
                                fragment.findNavController().navigate(action)
                            } catch (ex: Exception) {
                            }
                        }
                    }

                }
                NativePageType.LubricationDetail, NativePageType.MaintenanceDetail -> {
                    map?.get("taskId")?.toString()?.let { taskId ->
                        fragment.requireActivity().apply {
                            runOnUiThread {
                                val action =
                                    WebViewFragmentDirections.actionWebViewFragmentToLubricationTaskDetailFragment(
                                        taskId,
                                        if (page == NativePageType.LubricationDetail) TaskModuleType.LUBRICATION else TaskModuleType.MAINTENANCE
                                    )
                                fragment.findNavController().navigate(action)
                            }
                        }
                    }
                }
                NativePageType.SpotPatrolDetail -> {
                    map?.get("groupId")?.toString()?.let { groupId ->
                        map?.get("taskId")?.toString()?.toLongOrNull()?.let { taskId ->
                            fragment.requireActivity().apply {
                                runOnUiThread {
                                    val action =
                                        WebViewFragmentDirections.actionWebViewFragmentToTaskDetailFragment(
                                            groupId,
                                            taskId
                                        )
                                    fragment.findNavController().navigate(action)
                                }
                            }
                        }
                    }
                }
                NativePageType.RepairCreate -> {

                    var deviceId: Long = -1
                    map?.get("deviceId")?.let {
                        deviceId = getLongValue(it as Number)
                    }
                    val items: List<NativeParamsData> = listOf(
                        NativeParamsData(map?.get("deviceName").toString(),
                            deviceId,
                            map?.get("faultId").toString())
                    )

                    val paramsType =
                        Types.newParameterizedType(List::class.java, NativeParamsData::class.java)
                    val moshiAdapter = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
                        .adapter<List<NativeParamsData>>(paramsType)

                    FlutterModule.nativeParams = moshiAdapter.toJson(items.toList())

                    fragment.requireActivity().apply {
                        runOnUiThread {
                            val action =
                                WebViewFragmentDirections.actionWebViewFragmentToNativeFlutterFragment(
                                    FlutterModule.flutterEngineId,
                                    FlutterModule.repairCreate
                                )
                            fragment.findNavController().navigate(action)
                            fragment.webViewRefresh = true
                        }
                    }
                }
            }
        }

    }

    private fun sendCallback(result: String) {
        val jsString = "window.JSSDK.callback('$result')"
        Log.d(TAG, "Send callback $result.")
        webView.evaluateJavascript(jsString) {
            Log.d(TAG, it)
        }
    }


    /**
     * 选人组件
     */
    @JavascriptInterface
    fun selectMember(json: String) {

        ARouter.getInstance()
            .build(MineRoute.MEMBER_SELECT)
            .withString("json", json)
            .navigation()
//        val intent = Intent(fragment.requireContext(), SelectMemberActivity::class.java).putExtra(
//            "json",
//            json
//        )
//        if (fragment.requireActivity() is MainActivity) {
//            (fragment.requireActivity() as MainActivity).register.launch(intent)
//        }
    }

    companion object {
        private const val TAG = "WebViewInterface"
    }
}